# Import the base Model class from Flask-AppBuilder.
from flask_appbuilder import Model
# Import column types from SQLAlchemy to define database schema.
from sqlalchemy import Column, Integer, String, Text

# Import custom error and response classes from the application.
from myapp.const.error import CommonErrorCode
from myapp.const.response import BizError
# Import custom base models and mixins.
from myapp.models.base import MyappModelBase
from myapp.models.helpers import AuditMixinNullable


# Get the metadata from the base Flask-AppBuilder Model.
# This metadata object holds the schema information for all SQLAlchemy models.
metadata = Model.metadata


# Define the Prompt class, which maps to the 'prompt' table in the database.
# It inherits from Flask-AppBuilder's Model, our custom AuditMixin, and a base model.
class Prompt(Model, AuditMixinNullable, MyappModelBase):
    # Specify the table name in the database.
    __tablename__ = 'prompt'
    # Define the primary key column for the table.
    id = Column(Integer, primary_key=True, comment='id')

    # A string-based identifier for the prompt template.
    id_str = Column(String(200), nullable=True, comment='模板id')
    # The name of the prompt.
    name = Column(String(200), nullable=True, comment='任务名称')
    # The type of model this prompt is compatible with (e.g., 'language', 'visual').
    model_type = Column(String(200), nullable=True, comment='支持的模型分类: language/visual')
    # Labels for categorizing the prompt.
    labels = Column(String(200), nullable=True, comment='模板分类')
    # The actual content of the prompt template.
    content = Column(Text, nullable=True, comment='模板内容')
    # The ID of the parent template from which this one was derived. '0' indicates a built-in template.
    parent_id = Column(String(200), nullable=False, comment='来源模板id，为0时表示是内置模板')
    # A group identifier: 1 for built-in templates, 2 for user-created templates.
    group = Column(Integer, nullable=False, comment='1内置模板 2我的模板')
    # A string (e.g., JSON) storing paths to any resource files the prompt depends on, like images.
    files = Column(String(500), nullable=True, comment='模板依赖的资源，如图片地址')

    @staticmethod
    def get_by_id(prompt_id):
        """
        Retrieves a Prompt record by its integer ID or string ID.
        :param prompt_id: The ID (integer or string) of the prompt to retrieve.
        :return: The Prompt ORM object.
        :raises BizError: If the prompt_id is not provided or not found.
        """
        # Lazily import the db session to avoid circular dependencies.
        from myapp.app import db

        # Validate that a prompt_id was provided.
        if prompt_id is None:
            raise BizError(CommonErrorCode.INVALID_INPUT_PARAM, '必须指定模板ID')
        # Start a query on the Prompt model.
        query = db.session.query(Prompt)
        # First, try to find the prompt by its integer primary key.
        data = query.filter(Prompt.id == prompt_id).first()
        # If not found, try to find it by its string-based ID.
        if data is None:
            data = query.filter(Prompt.id_str == prompt_id).first()
            # If still not found after both checks, raise a "Not Found" error.
            if data is None:
                raise BizError(CommonErrorCode.NOT_FOUND, f'模板ID不存在:{prompt_id}')
        # Return the found prompt object.
        return data

    @staticmethod
    def check_name_exist(name, uid):
        """
        Checks if a prompt with the given name already exists for a specific user.
        :param name: The name of the prompt to check.
        :param uid: The ID of the user.
        :raises BizError: If a prompt with the same name already exists for the user.
        """
        # Lazily import the db session.
        from myapp.app import db

        # Query for a prompt with the same name and created by the same user.
        p = (
            db.session.query(Prompt)
            .filter(Prompt.name == name)
            .filter(Prompt.created_by_fk == uid)
            .first()
        )
        # If a record is found, it's a duplicate. Raise an error.
        if p is not None:
            raise BizError(CommonErrorCode.INVALID_INPUT_PARAM, '模板名称重复')

    @staticmethod
    def get_copy_cnt(parent_id_str, uid):
        """
        Counts how many times a user has copied a specific parent prompt.
        This is used to generate unique names for copies (e.g., "Copy of X (2)").
        :param parent_id_str: The string ID of the parent prompt.
        :param uid: The ID of the user.
        :return: The number of existing copies plus one.
        """
        # Lazily import the db session.
        from myapp.app import db

        # Count the number of prompts created by the user that have the specified parent_id.
        i = (
            db.session.query(Prompt)
            .filter(Prompt.parent_id == parent_id_str)
            .filter(Prompt.created_by_fk == uid)
            .count()
        )
        # Return the count plus one to get the next copy number.
        return i + 1
